package com.zmn.oms.business.impl.work;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.zmn.common.constant.FicoConsts;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.constant.StatusConsts;
import com.zmn.common.utils.amount.AmountUtil;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.math.MathUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.dms.common.enums.coup.ThirdPlatEnum;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.manager.redis.RedisManager;
import com.zmn.oms.business.interfaces.discount.OrderDiscountBService;
import com.zmn.oms.business.interfaces.orderamount.OrderDiscountCalcBService;
import com.zmn.oms.business.interfaces.serviceitem.OrderServiceItemBService;
import com.zmn.oms.business.interfaces.work.OrderWorkAmountBService;
import com.zmn.oms.common.annotation.OrderWorkChangeSync;
import com.zmn.oms.common.annotation.ZsNormalOrderWorkLog;
import com.zmn.oms.common.constant.*;
import com.zmn.oms.common.dio.normal.orderadd.OrderPayDiscountDIO;
import com.zmn.oms.common.dro.orderpay.OrderPayResultDRO;
import com.zmn.oms.common.dto.OmsRefundRequestDTO;
import com.zmn.oms.common.enums.RefundInitiateTypeEnum;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.constant.MessageQueueTopicConstant;
import com.zmn.oms.model.bo.orderamount.OrderAmountCalcBO;
import com.zmn.oms.model.bo.orderamount.OrderDiscountCalcBO;
import com.zmn.oms.model.bo.work.ChangeOriginalAmountDiscountBO;
import com.zmn.oms.model.bo.work.OrderWorkAmountBO;
import com.zmn.oms.model.dto.work.refund.WorkRefundResultDTO;
import com.zmn.oms.model.dto.work.workamount.*;
import com.zmn.oms.model.entity.discount.OrderDiscount;
import com.zmn.oms.model.entity.product.OrderProductExtend;
import com.zmn.oms.model.entity.serviceitem.OrderServiceItem;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.services.interfaces.discount.OrderDiscountService;
import com.zmn.oms.services.interfaces.member.OrderMemberService;
import com.zmn.oms.services.interfaces.product.OrderProductExtendService;
import com.zmn.oms.services.interfaces.product.OrderProductService;
import com.zmn.oms.services.interfaces.serviceitem.OrderServiceItemService;
import com.zmn.oms.services.interfaces.work.OrderWorkAmountService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.pay.common.constant.PayConsts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 类描述：工单金额业务实现
 *
 * @author heciqi
 * @date 2018/11/02 21:02
 */
@Slf4j
@Service
public class OrderWorkAmountBServiceImpl implements OrderWorkAmountBService {

    private static final Logger logger = LoggerFactory.getLogger(OrderWorkAmountBServiceImpl.class);

    @Autowired
    OrderWorkAmountService orderWorkAmountService;
    @Autowired
    OrderWorkService orderWorkService;
    @Autowired
    OrderDiscountService orderDiscountService;
    @Autowired
    OrderDiscountBService orderDiscountBService;
    @Autowired
    OrderProductService orderProductService;
    @Autowired
    OrderMemberService orderMemberService;
    @Autowired
    OrderServiceItemBService orderServiceItemBService;
    @Autowired
    OrderWorkAmountBService orderWorkAmountBService;
    @Autowired
    OrderServiceItemService orderServiceItemService;
    @Autowired
    OrderProductExtendService orderProductExtendService;
    @Autowired
    OrderDiscountCalcBService orderDiscountCalcBService;
    @Autowired
    RedisManager redisManager;
    @Autowired
    ZmnMQSender zmnMQSender;


    @Override
    public void updateOriginalAmount(WorkUpdateAmountDTO updateAmountDTO) throws OmsBaseException {
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKeySrcMaster(updateAmountDTO.getOrderId(), updateAmountDTO.getWorkId());
        CheckUpdateAmountResultDTO updateAmountResultDTO = checkOriginalAmount(updateAmountDTO, dbOrderWork);

        // 原价引起优惠发生变更
        ChangeOriginalAmountDiscountBO discountBO = updateAmountResultDTO.getDiscountBO();
        List<OrderDiscount> orderDiscountList = discountBO.getOrderDiscountList();
        if (orderDiscountList != null && orderDiscountList.size() != 0) {
            // 保存优惠 (先删后增)
            orderDiscountBService.saveOrderDiscountList(orderDiscountList, updateAmountDTO.getOrderId());
        }

        OrderWorkAmountBO amountBO = new OrderWorkAmountBO();
        amountBO.setOrderId(dbOrderWork.getOrderId());
        amountBO.setWorkId(dbOrderWork.getWorkId());
        amountBO.setOriginalAmount(updateAmountDTO.getOriginalAmount());
        amountBO.setDiscountAmount(discountBO.getDiscountAmount());
        amountBO.setOnlyVisit(updateAmountDTO.getOnlyVisit());
        processMasterAndTotalAmount(amountBO, dbOrderWork);
    }

    @Override
    public void deleteOriginalAmount(WorkUpdateAmountDTO updateAmountDTO) throws OmsBaseException {

        // 订单金额
        Integer originalAmount = updateAmountDTO.getOriginalAmount();
        if (originalAmount == null) {
            throw new OmsBaseException("非法操作 原价不为空");
        }
        // 清洗 -》 维修
        // 有优惠先删除所有的优惠
        // 如果是会员单重新计算会员优惠
        // 设置优惠总金额 订单金额 订单收入 工程师收款金额 为空
        CheckUpdateAmountResultDTO updateAmountResultDTO = checkDeleteOriginalAmount(updateAmountDTO);

        // 原价引起优惠发生变更
        ChangeOriginalAmountDiscountBO discountBO = updateAmountResultDTO.getDiscountBO();
        List<OrderDiscount> orderDiscountList = discountBO.getOrderDiscountList();
        if (orderDiscountList != null && orderDiscountList.size() != 0) {
            // 保存优惠 (先删后增)
            orderDiscountBService.saveOrderDiscountList(orderDiscountList, updateAmountDTO.getOrderId());
        }

        // 清空 订单金额 订单收入 工程师收款金额  优惠总金额
        orderWorkAmountService.deleteOriginalAmount(updateAmountDTO.getOrderId(), updateAmountDTO.getWorkId());
    }

    /**
     * 检查删除原价接口
     *
     * @param updateAmountDTO
     * @return
     * @throws OmsBaseException
     */
    private CheckUpdateAmountResultDTO checkDeleteOriginalAmount(WorkUpdateAmountDTO updateAmountDTO) throws OmsBaseException {
        Long orderId = updateAmountDTO.getOrderId();
        Long workId = updateAmountDTO.getWorkId();

        // 检查原价应该为空
        Integer originalAmount = updateAmountDTO.getOriginalAmount();
        if (originalAmount == null) {
            throw new OmsBaseException("非法操作 原价不为空");
        }

        // 如果有优惠则先删除所有优惠
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKeySrcMaster(orderId, workId);
        if (dbOrderWork.getDiscountAmount() != null && dbOrderWork.getDiscountAmount() != 0) {
            orderDiscountService.deleteByOrderId(orderId);
        }

        // 如果是会员单则需要重新计算优惠
        updateAmountDTO.setOriginalAmount(0);
        ChangeOriginalAmountDiscountBO discountBO = getDiscountAmountByOriginalAmountChange(updateAmountDTO, dbOrderWork);

        // 优惠总金额
        CheckUpdateAmountResultDTO updateAmountResultDTO = new CheckUpdateAmountResultDTO();
        updateAmountResultDTO.setDbOrderWork(dbOrderWork);
        updateAmountResultDTO.setDiscountBO(discountBO);
        return updateAmountResultDTO;
    }

    /**
     * 修改预付款
     *
     * @param amountDTO
     */
    @Override
    @OrderWorkChangeSync
    public void updatePrepayAmount(WorkAmountDTO amountDTO) throws OmsBaseException {

        int amount = amountDTO.isRemove() ? GlobalConsts.NONE : amountDTO.getAmount();
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKey(amountDTO.getOrderId(), amountDTO.getWorkId());

        WorkUpdateAmountDTO updateAmountDTO = new WorkUpdateAmountDTO();
        updateAmountDTO.setWorkId(amountDTO.getWorkId());
        updateAmountDTO.setOrderId(amountDTO.getOrderId());
        updateAmountDTO.setPrepayAmount(amount);

        // 校验
        checkPrepayAmount(updateAmountDTO);

        OrderWorkAmountBO amountBO = new OrderWorkAmountBO();
        amountBO.setOrderId(amountDTO.getOrderId());
        amountBO.setWorkId(amountDTO.getWorkId());
        amountBO.setPrepayAmount(amount);
        processMasterAndTotalAmount(amountBO, dbOrderWork);

        // 删除状态 设置支付状态 0
        if (amountDTO.isRemove()) {
            OrderWork updateOrderWork = new OrderWork();
            updateOrderWork.setWorkId(amountDTO.getWorkId());
            updateOrderWork.setOrderId(amountDTO.getOrderId());
            updateOrderWork.setPrepayAmount(null);
            updateOrderWork.setPrepayStatus(GlobalConsts.NONE);
            updateOrderWork.setDisableDiscard(GlobalConsts.NO);
            updateOrderWork.setFullPaymentFlag(GlobalConsts.NO);
            orderWorkAmountService.updatePrepayAmount(updateOrderWork);
        }
    }

    /**
     * 预付款支付
     *
     * @param orderWorkPayDTO
     */
    @Override
    public void updatePrepayAmountPay(WorkPayDTO orderWorkPayDTO) {
        // 更新工单金额
        OrderWork orderWork = new OrderWork();
        orderWork.setWorkId(orderWorkPayDTO.getWorkId());
        orderWork.setPrepayAmount(orderWorkPayDTO.getAmount());
        orderWork.setPrepayChannelId(orderWorkPayDTO.getPayChannelId());
        orderWork.setPrepayStatus(orderWorkPayDTO.getPayStatus());
        orderWork.setPrepayTime(orderWorkPayDTO.getPayTime());
        // 计算原价，和应收
        WorkCollectAmountDTO collectAmount = this.getCollectAmount(null);
        orderWork.setOriginalAmount(collectAmount.getOriginalAmount());
        orderWork.setTotalAmount(collectAmount.getTotalAmount());
        orderWorkAmountService.updatePrepayAmountPay(orderWork);

        // TODO 调用财务接口生成凭证
    }

    /**
     * 修改定金
     *
     * @param updateAmountDTO
     */
    @Override
    public void updateDepositAmount(WorkUpdateAmountDTO updateAmountDTO) throws OmsBaseException {

        CheckUpdateAmountResultDTO updateAmountResultDTO = checkDepositAmount(updateAmountDTO);

        // 计算应收，订单金额
        // 改定金 重新计算 订单收入 工程师收款金额
        OrderWork dbOrderWork = updateAmountResultDTO.getDbOrderWork();

        OrderWorkAmountBO amountBO = new OrderWorkAmountBO();
        amountBO.setOrderId(dbOrderWork.getOrderId());
        amountBO.setWorkId(dbOrderWork.getWorkId());
        amountBO.setDepositAmount(updateAmountDTO.getDepositAmount());
        amountBO.setOnlyVisit(updateAmountDTO.getOnlyVisit());
        processMasterAndTotalAmount(amountBO, dbOrderWork);
    }

    /**
     * 定金支付
     *
     * @param orderWorkPayDTO
     */
    @Override
    public void updateDepositAmountPay(WorkPayDTO orderWorkPayDTO) {
        // 更新工单金额
        OrderWork orderWork = new OrderWork();
        orderWork.setWorkId(orderWorkPayDTO.getWorkId());
        orderWork.setDepositAmount(orderWorkPayDTO.getAmount());
        orderWork.setDepositChannelId(orderWorkPayDTO.getPayChannelId());
        orderWork.setDepositStatus(orderWorkPayDTO.getPayStatus());
        orderWork.setDepositTime(orderWorkPayDTO.getPayTime());
        // 计算应收，订单金额
        WorkCollectAmountDTO collectAmount = this.getCollectAmount(null);
        orderWork.setOriginalAmount(collectAmount.getOriginalAmount());
        orderWork.setTotalAmount(collectAmount.getTotalAmount());
        orderWorkAmountService.updatePrepayAmountPay(orderWork);

        // TODO 调用财务接口生成凭证
    }

    /**
     * 修改优惠金额 （优惠总金额）
     *
     * @param workAmountDTO
     */
    @Override
    public void updateDiscountAmount(WorkAmountDTO workAmountDTO) throws OmsBaseException {

        // 校验
        CheckUpdateAmountResultDTO updateAmountResultDTO = checkDiscountAmount(workAmountDTO);
        OrderWork dbOrderWork = updateAmountResultDTO.getDbOrderWork();

        OrderWorkAmountBO amountBO = new OrderWorkAmountBO();
        amountBO.setOrderId(dbOrderWork.getOrderId());
        amountBO.setWorkId(dbOrderWork.getWorkId());
        amountBO.setDiscountAmount(workAmountDTO.getAmount());
        processMasterAndTotalAmount(amountBO, dbOrderWork);
    }

    @Override
    public void updateDiscountAmountPay(WorkPayDTO orderWorkPayDTO) {
        // TODO 调用财务接口生成凭证
    }

    /**
     * 修改退款金额
     *
     * @param orderWorkAmountDTO
     */
    @Override
    public void updateRefundAmount(WorkAmountDTO orderWorkAmountDTO) {
        // TODO 获取之前的退款金额
        Integer originalRefundAmount = 0;
        // 总退款金额
        int refundAmount = originalRefundAmount + orderWorkAmountDTO.getAmount();

        OrderWork orderWork = new OrderWork();
        orderWork.setWorkId(orderWorkAmountDTO.getWorkId());
        orderWork.setRefundAmount(refundAmount);

        // 计算原价，和应收
        WorkCollectAmountDTO collectAmount = this.getCollectAmount(orderWorkAmountDTO);
        orderWork.setOriginalAmount(collectAmount.getOriginalAmount());
        orderWork.setTotalAmount(collectAmount.getTotalAmount());

        orderWorkAmountService.updateDiscountAmount(orderWork);
    }

    @Override
    public void updateRefundAmountPay(WorkPayDTO orderWorkPayDTO) {
        // TODO 调用财务接口生成凭证
    }

    /**
     * 更新配件金额
     *
     * @param orderWork
     * @return 影响行数
     */
    @Override
    public void updatePartAmount(OrderWork orderWork) {
        orderWorkAmountService.updatePartAmount(orderWork);
    }

    @Override
    public void updateOriginalAndDepositAmount(WorkUpdateAmountDTO updateAmountDTO) throws OmsBaseException {

        // 检查原价和定金是否可以修改
        CheckUpdateAmountResultDTO updateAmountResultDTO = checkOriginalAndDepositAmount(updateAmountDTO);

        // 原价引起优惠发生变更
        ChangeOriginalAmountDiscountBO discountBO = updateAmountResultDTO.getDiscountBO();
        List<OrderDiscount> orderDiscountList = discountBO.getOrderDiscountList();
        if (orderDiscountList != null && orderDiscountList.size() != 0) {
            // 保存优惠 (先删后增)
            orderDiscountBService.saveOrderDiscountList(orderDiscountList, updateAmountDTO.getOrderId());
        }

        // 改原价 定金 优惠 重新计算 订单收入  工程师收款金额
        OrderWork dbOrderWork = updateAmountResultDTO.getDbOrderWork();

        OrderWorkAmountBO amountBO = new OrderWorkAmountBO();
        amountBO.setOrderId(dbOrderWork.getOrderId());
        amountBO.setWorkId(dbOrderWork.getWorkId());
        amountBO.setOriginalAmount(updateAmountDTO.getOriginalAmount());
        amountBO.setDepositAmount(updateAmountDTO.getDepositAmount());
        amountBO.setDiscountAmount(discountBO.getDiscountAmount());
        amountBO.setOnlyVisit(updateAmountDTO.getOnlyVisit());
        processMasterAndTotalAmount(amountBO, dbOrderWork);
    }

    @Override
    public void updateChannelPrepayAmount(WorkUpdateAmountDTO updateAmountDTO) throws OmsBaseException {

        CheckUpdateAmountResultDTO updateAmountResultDTO = checkChannelPrepayAmount(updateAmountDTO);

        // 计算应收，订单金额
        // 改定金 重新计算 订单收入 工程师收款金额
        OrderWork dbOrderWork = updateAmountResultDTO.getDbOrderWork();

        OrderWorkAmountBO amountBO = new OrderWorkAmountBO();
        amountBO.setOrderId(dbOrderWork.getOrderId());
        amountBO.setWorkId(dbOrderWork.getWorkId());
        amountBO.setChannelPrepayAmount(updateAmountDTO.getChannelPrepayAmount());
        amountBO.setChannelPrepayStatus(updateAmountDTO.getChannelPrepayStatus());
        amountBO.setOnlyVisit(updateAmountDTO.getOnlyVisit());
        processMasterAndTotalAmountByChannelPrepay(amountBO, dbOrderWork);
    }

    /**
     * 获取汇总的金额（订单收入、订单金额）
     *
     * @return
     */
    protected WorkCollectAmountDTO getCollectAmount(WorkAmountDTO orderWorkAmountDto) {
        WorkCollectAmountDTO collectAmountDTO = new WorkCollectAmountDTO();
        collectAmountDTO.setOriginalAmount(0);
        collectAmountDTO.setTotalAmount(0);
        return collectAmountDTO;
    }

    /**
     * 获取原价变动后的优惠总金额
     *
     * @param updateAmountDTO 订单金额
     * @param dbOrderWork     工单Id
     * @return
     */
    @Override
    public ChangeOriginalAmountDiscountBO getDiscountAmountByOriginalAmountChange(WorkUpdateAmountDTO updateAmountDTO, OrderWork dbOrderWork) throws OmsBaseException {

        // 返回结果集
        ChangeOriginalAmountDiscountBO discountBO = new ChangeOriginalAmountDiscountBO();

        // 订单金额
        Integer originalAmount = updateAmountDTO.getOriginalAmount();

        // 筛选出折扣类型的优惠
        List<OrderDiscount> discountList = orderDiscountService.listByOrderIdSrcMaster(dbOrderWork.getOrderId());
        logger.debug("优惠列表{}",discountList);

        // 2.非会员折扣需要重新计算
        Integer unMemberRebateAmount = 0;
        List<OrderDiscount> unMemberRebateDiscountList = discountList.stream().filter(discount -> {
            boolean unMember = !Objects.equals(discount.getCateg(), FicoConsts.ORDER_IN_DISCOUNT_CATEG_MEMBER);
            boolean isRebate = Objects.equals(discount.getType(), OrderConsts.ORDER_DISCOUNT_TYPE_DISCOUNT);
            return isRebate && unMember;
        }).collect(Collectors.toList());

        // 新的非会员折扣list
        List<OrderDiscount> unMemberRebateNewDiscountList = Lists.newArrayList();
        for (OrderDiscount discount : unMemberRebateDiscountList) {
            JSONObject sourceData = JSON.parseObject(discount.getSourceData());
            Double discountValue = sourceData.getDouble("discountValue");
            double amount;
            if (discountValue != null) {
                amount = MathUtil.mul(originalAmount, discountValue);
            } else {
                amount = discount.getAmount();
            }
            discount.setAmount((int) amount);
            unMemberRebateNewDiscountList.add(discount);
            unMemberRebateAmount = (int) MathUtil.add(unMemberRebateAmount, amount);
        }

        // 3.非会员立减不需要重新需要
        Integer unMemberLimitAmount = 0;
        List<OrderDiscount> unMemberLimitDiscountList = discountList.stream().filter(discount -> {
            boolean unMember = !Objects.equals(discount.getCateg(), FicoConsts.ORDER_IN_DISCOUNT_CATEG_MEMBER);
            boolean isLimit = Objects.equals(discount.getType(), OrderConsts.ORDER_DISCOUNT_TYPE_LIMIT_FREE);
            return isLimit && unMember;
        }).collect(Collectors.toList());
        List<OrderDiscount> unMemberLimitNewDiscountList = Lists.newArrayList();
        for (OrderDiscount discount : unMemberLimitDiscountList) {
            unMemberLimitAmount += discount.getAmount();
        }
        unMemberLimitNewDiscountList = unMemberLimitDiscountList;

        // 4.非会员全免需要重新计算
        Integer unMemberFreeAmount = 0;
        List<OrderDiscount> unMemberFreeDiscountList = discountList.stream().filter(discount -> {
            boolean unMember = !Objects.equals(discount.getCateg(), FicoConsts.ORDER_IN_DISCOUNT_CATEG_MEMBER);
            boolean isFree = Objects.equals(discount.getType(), OrderConsts.ORDER_DISCOUNT_TYPE_FREE);
            return isFree && unMember;
        }).collect(Collectors.toList());
        List<OrderDiscount> unMemberFreeNewDiscountList = Lists.newArrayList();
        for (OrderDiscount discount : unMemberFreeDiscountList) {
            discount.setAmount(originalAmount);
            unMemberFreeAmount = originalAmount;
            unMemberFreeNewDiscountList.add(discount);
        }

        // 优惠金额 （再将1,2,3,4优惠项计算出总的）
        Integer discountAmount = unMemberRebateAmount + unMemberLimitAmount + unMemberFreeAmount;

        List<OrderDiscount> orderDiscountList = Lists.newArrayList();

        orderDiscountList.addAll(unMemberRebateNewDiscountList);
        orderDiscountList.addAll(unMemberLimitNewDiscountList);
        orderDiscountList.addAll(unMemberFreeNewDiscountList);

        discountBO.setDiscountAmount(discountAmount);
        discountBO.setOrderDiscountList(orderDiscountList);

        logger.debug("discountBO[{}]",discountBO);
        return discountBO;
    }

    /**
     * 检查定金和预付款是否可以修改
     *
     * @param updateAmountDTO
     * @return
     * @throws OmsBaseException
     */
    private CheckUpdateAmountResultDTO checkOriginalAndDepositAmount(WorkUpdateAmountDTO updateAmountDTO) throws OmsBaseException {
        Long orderId = updateAmountDTO.getOrderId();
        Long workId = updateAmountDTO.getWorkId();
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKeySrcMaster(orderId, workId);

        // 订单金额
        Integer originalAmount = updateAmountDTO.getOriginalAmount();
        // 定金
        Integer depositAmount = updateAmountDTO.getDepositAmount();
        if (originalAmount == null || depositAmount == null) {
            throw new OmsBaseException("非法操作 原价或定金为空");
        }

        // 优惠总金额
        ChangeOriginalAmountDiscountBO discountBO = getDiscountAmountByOriginalAmountChange(updateAmountDTO, dbOrderWork);
        Integer discountAmount = discountBO.getDiscountAmount();

        // 预付款 = (啄木鸟预收 + 渠道预收)
        Integer prepayAmount = Optional.ofNullable(dbOrderWork.getPrepayAmount()).orElse(0);
        Integer channelPrepayAmount = Optional.ofNullable(dbOrderWork.getChannelPrepayAmount()).orElse(0);

        // 边界公式：订单金额 ≥ 优惠 + 预付款 + 定金
        // 不满足公式，非标准单提示：原价需大于：xx
        // 不满足公式，标准单提示：定金需小于：xx
        validateWorkAmount(originalAmount, discountAmount, prepayAmount, channelPrepayAmount, depositAmount);

        CheckUpdateAmountResultDTO updateAmountResultDTO = new CheckUpdateAmountResultDTO();
        updateAmountResultDTO.setDbOrderWork(dbOrderWork);
        updateAmountResultDTO.setDiscountBO(discountBO);
        return updateAmountResultDTO;
    }

    /**
     * 更新 工程师收款金额 和 订单收入
     *
     * @param amountBO
     * @param dbOrderWork
     */
    private void processMasterAndTotalAmount(OrderWorkAmountBO amountBO, OrderWork dbOrderWork) throws OmsBaseException {

        // 工程师收款金额 = 订单金额 - (优惠总额 + 啄木鸟预收 + 渠道预收 + 定金 + 退款金额)
        // 订单收入 = 订单金额 - 优惠总额 - 退款金额

        // 订单金额
        Integer originalAmount = amountBO.getOriginalAmount();
        originalAmount = Optional.ofNullable(originalAmount).orElse(Optional.ofNullable(dbOrderWork.getOriginalAmount()).orElse(0));

        // 定金
        Integer depositAmount = amountBO.getDepositAmount();
        depositAmount = Optional.ofNullable(depositAmount).orElse(Optional.ofNullable(dbOrderWork.getDepositAmount()).orElse(0));

        // 啄木鸟预收
        Integer prepayAmount = amountBO.getPrepayAmount();
        prepayAmount = Optional.ofNullable(prepayAmount).orElse(Optional.ofNullable(dbOrderWork.getPrepayAmount()).orElse(0));

        // 渠道预收
        Integer channelPrepayAmount = amountBO.getChannelPrepayAmount();
        channelPrepayAmount = Optional.ofNullable(channelPrepayAmount).orElse(Optional.ofNullable(dbOrderWork.getChannelPrepayAmount()).orElse(0));

        // 优惠总额
        Integer discountAmount = amountBO.getDiscountAmount();
        discountAmount = Optional.ofNullable(discountAmount).orElse(Optional.ofNullable(dbOrderWork.getDiscountAmount()).orElse(0));
        logger.info("工单优惠金额为：orderId:{},discountAmount:{}",dbOrderWork.getOrderId(),discountAmount);
        // 退款总额
        Integer refundAmount = amountBO.getRefundAmount();
        refundAmount = Optional.ofNullable(refundAmount).orElse(Optional.ofNullable(dbOrderWork.getRefundAmount()).orElse(0));

        // 工程师收款金额 = 订单金额 - (优惠总额 + 啄木鸟预收 + 渠道预收 + 定金 + 退款金额)
        Integer addAmount = depositAmount + prepayAmount + channelPrepayAmount + discountAmount + refundAmount;
        Integer masterAmount = originalAmount - addAmount;

        // 订单收入 = 订单金额 - 优惠总额
        Integer totalAmount = originalAmount - discountAmount - refundAmount;

        // 是否标记上门费
        Integer onlyVisit = amountBO.getOnlyVisit();
        onlyVisit = Optional.ofNullable(onlyVisit).orElse(Optional.ofNullable(dbOrderWork.getOnlyVisit()).orElse(0));
/*        if (Objects.equals(onlyVisit, GlobalConsts.YES)) {
            if (masterAmount > 3000) {
                throw new OmsBaseException("工程师收款金额大于30无法设置上门费");
            }
        }*/

        OrderWork orderWork = new OrderWork();
        orderWork.setOrderId(dbOrderWork.getOrderId());
        orderWork.setWorkId(dbOrderWork.getWorkId());

        boolean isZero = (originalAmount == 0 && addAmount == 0);

        // 原价为零 不需要设置应收和工程师收款金额
        if (!Objects.equals(GlobalConsts.NONE, originalAmount) || isZero) {
            orderWork.setOriginalAmount(originalAmount);
            orderWork.setTotalAmount(totalAmount);
            orderWork.setMasterAmount(masterAmount);
        }

        orderWork.setPrepayAmount(prepayAmount == 0 ? null : prepayAmount);
        orderWork.setChannelPrepayAmount(channelPrepayAmount == 0 ? null : channelPrepayAmount);
        orderWork.setDepositAmount(depositAmount == 0 ? null : depositAmount);
        orderWork.setDiscountAmount(discountAmount == 0 ? null : discountAmount);
        orderWork.setOnlyVisit(onlyVisit);
        orderWorkAmountService.updateAmount(orderWork);
    }

    /**
     * 更新 工程师收款金额 和 订单收入
     *
     * @param amountBO
     * @param dbOrderWork
     */
    private void processMasterAndTotalAmountByChannelPrepay(OrderWorkAmountBO amountBO, OrderWork dbOrderWork) throws OmsBaseException {

        // 工程师收款金额 = 订单金额 - (优惠总额 + 啄木鸟预收 + 渠道预收 + 定金 + 退款金额)
        // 订单收入 = 订单金额 - 优惠总额 - 退款金额

        // 订单金额
        Integer originalAmount = amountBO.getOriginalAmount();
        originalAmount = Optional.ofNullable(originalAmount).orElse(Optional.ofNullable(dbOrderWork.getOriginalAmount()).orElse(0));

        // 定金
        Integer depositAmount = amountBO.getDepositAmount();
        depositAmount = Optional.ofNullable(depositAmount).orElse(Optional.ofNullable(dbOrderWork.getDepositAmount()).orElse(0));

        // 啄木鸟预收
        Integer prepayAmount = amountBO.getPrepayAmount();
        prepayAmount = Optional.ofNullable(prepayAmount).orElse(Optional.ofNullable(dbOrderWork.getPrepayAmount()).orElse(0));

        // 渠道预收
        Integer channelPrepayAmount = amountBO.getChannelPrepayAmount();
        channelPrepayAmount = Optional.ofNullable(channelPrepayAmount).orElse(Optional.ofNullable(dbOrderWork.getChannelPrepayAmount()).orElse(0));

        // 优惠总额
        Integer discountAmount = amountBO.getDiscountAmount();
        discountAmount = Optional.ofNullable(discountAmount).orElse(Optional.ofNullable(dbOrderWork.getDiscountAmount()).orElse(0));

        // 退款总额
        Integer refundAmount = amountBO.getRefundAmount();
        refundAmount = Optional.ofNullable(refundAmount).orElse(Optional.ofNullable(dbOrderWork.getRefundAmount()).orElse(0));

        // 工程师收款金额 = 订单金额 - (优惠总额 + 啄木鸟预收 + 渠道预收 + 定金 + 退款)
        Integer addAmount = depositAmount + prepayAmount + channelPrepayAmount + discountAmount + refundAmount;
        Integer masterAmount = originalAmount - addAmount;

        // 订单收入 = 订单金额 - 优惠总额 - 退款金额
        Integer totalAmount = originalAmount - discountAmount - refundAmount;

        // 是否标记上门费
        Integer onlyVisit = amountBO.getOnlyVisit();
        onlyVisit = Optional.ofNullable(onlyVisit).orElse(Optional.ofNullable(dbOrderWork.getOnlyVisit()).orElse(0));
        if (Objects.equals(onlyVisit, GlobalConsts.YES)) {
            if (masterAmount > 3000) {
                throw new OmsBaseException("工程师收款金额大于30无法设置上门费");
            }
        }

        OrderWork orderWork = new OrderWork();
        orderWork.setOrderId(dbOrderWork.getOrderId());
        orderWork.setWorkId(dbOrderWork.getWorkId());

        // 原价为零 不需要设置应收和工程师收款金额
        // 未有原价改预付款时 不需要修改原价应收 工程师收款金额
        if (!Objects.equals(originalAmount, GlobalConsts.NONE)) {
            orderWork.setOriginalAmount(originalAmount);
            orderWork.setTotalAmount(totalAmount);
            orderWork.setMasterAmount(masterAmount);
        }

        orderWork.setPrepayAmount(prepayAmount == 0 ? null : prepayAmount);
        orderWork.setChannelPrepayAmount(channelPrepayAmount == 0 ? null : channelPrepayAmount);
        orderWork.setChannelPrepayStatus(amountBO.getChannelPrepayStatus());
        orderWork.setDepositAmount(depositAmount == 0 ? null : depositAmount);
        orderWork.setDiscountAmount(discountAmount == 0 ? null : discountAmount);
        orderWork.setOnlyVisit(onlyVisit);
        orderWorkAmountService.updateAmount(orderWork);
    }

    /**
     * 检查原价是否可以修改
     *
     * @param updateAmountDTO
     * @return
     * @throws OmsBaseException
     */
    private CheckUpdateAmountResultDTO checkOriginalAmount(WorkUpdateAmountDTO updateAmountDTO, OrderWork dbOrderWork) throws OmsBaseException {
        logger.info("[{}]检查原价checkOriginalAmount[{}]",dbOrderWork.getWorkId(),updateAmountDTO);
        // 订单金额
        Integer originalAmount = updateAmountDTO.getOriginalAmount();
        if (originalAmount == null) {
            throw new OmsBaseException("非法操作 原价为空");
        }

        // 优惠总金额
        ChangeOriginalAmountDiscountBO discountBO = getDiscountAmountByOriginalAmountChange(updateAmountDTO, dbOrderWork);
        Integer discountAmount = discountBO.getDiscountAmount();

        // 预付款
        Integer prepayAmount = Optional.ofNullable(dbOrderWork.getPrepayAmount()).orElse(0);
        Integer channelPrepayAmount = Optional.ofNullable(dbOrderWork.getChannelPrepayAmount()).orElse(0);
        // 定金
        Integer depositAmount = Optional.ofNullable(dbOrderWork.getDepositAmount()).orElse(0);

        // 边界公式：订单金额 ≥ 优惠 + 预付款 + 定金
        // 不满足公式，非标准单提示：原价需大于：xx
        // 不满足公式，标准单提示：定金需小于：xx
        validateWorkAmount(originalAmount, discountAmount, prepayAmount, channelPrepayAmount, depositAmount);

        CheckUpdateAmountResultDTO updateAmountResultDTO = new CheckUpdateAmountResultDTO();
        updateAmountResultDTO.setDbOrderWork(dbOrderWork);
        updateAmountResultDTO.setDiscountBO(discountBO);
        return updateAmountResultDTO;
    }

    /**
     * 检查预付款是否可以修改
     *
     * @param updateAmountDTO
     * @return
     * @throws OmsBaseException
     */
    private CheckUpdateAmountResultDTO checkPrepayAmount(WorkUpdateAmountDTO updateAmountDTO) throws OmsBaseException {
        Long orderId = updateAmountDTO.getOrderId();
        Long workId = updateAmountDTO.getWorkId();
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKeySrcMaster(orderId, workId);

        // 啄木鸟预付
        Integer prepayAmount = updateAmountDTO.getPrepayAmount();

        if (prepayAmount == null) {
            throw new OmsBaseException("非法操作 啄木鸟预付为空");
        }

        // 定金
        Integer depositAmount = Optional.ofNullable(dbOrderWork.getDepositAmount()).orElse(0);
        // 订单金额
        Integer originalAmount = Optional.ofNullable(dbOrderWork.getOriginalAmount()).orElse(0);
        // 优惠金额
        Integer discountAmount = Optional.ofNullable(dbOrderWork.getDiscountAmount()).orElse(0);
        // 渠道预付款
        Integer channelPrepayAmount = Optional.ofNullable(dbOrderWork.getChannelPrepayAmount()).orElse(0);

        // 边界公式：订单金额 ≥ 优惠 + 预付款 + 定金
        // 不满足公式，非标准单提示：原价需大于：xx
        // 不满足公式，标准单提示：定金需小于：xx
        validateWorkAmount(originalAmount, discountAmount, prepayAmount, channelPrepayAmount, depositAmount);

        CheckUpdateAmountResultDTO resultDTO = new CheckUpdateAmountResultDTO();
        resultDTO.setDbOrderWork(dbOrderWork);
        return resultDTO;
    }

    /**
     * 检查定金是否可以修改
     *
     * @param updateAmountDTO
     * @return
     * @throws OmsBaseException
     */
    private CheckUpdateAmountResultDTO checkDepositAmount(WorkUpdateAmountDTO updateAmountDTO) throws OmsBaseException {
        Long orderId = updateAmountDTO.getOrderId();
        Long workId = updateAmountDTO.getWorkId();
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKeySrcMaster(orderId, workId);

        // 定金
        Integer depositAmount = updateAmountDTO.getDepositAmount();
        if (depositAmount == null) {
            throw new OmsBaseException("非法操作 定金为空");
        }

        // 订单金额
        Integer originalAmount = Optional.ofNullable(dbOrderWork.getOriginalAmount()).orElse(0);
        // 优惠金额
        Integer discountAmount = Optional.ofNullable(dbOrderWork.getDiscountAmount()).orElse(0);
        // 预付款
        Integer prepayAmount = Optional.ofNullable(dbOrderWork.getPrepayAmount()).orElse(0);
        // 渠道预付款
        Integer channelPrepayAmount = Optional.ofNullable(dbOrderWork.getChannelPrepayAmount()).orElse(0);

        // 边界公式：订单金额 ≥ 优惠 + 预付款 + 定金
        // 不满足公式，非标准单提示：原价需大于：xx
        // 不满足公式，标准单提示：定金需小于：xx
        validateWorkAmount(originalAmount, discountAmount, prepayAmount, channelPrepayAmount, depositAmount);

        CheckUpdateAmountResultDTO resultDTO = new CheckUpdateAmountResultDTO();
        resultDTO.setDbOrderWork(dbOrderWork);
        return resultDTO;
    }

    /**
     * 检查渠道预付是否可以修改
     *
     * @param updateAmountDTO
     * @return
     * @throws OmsBaseException
     */
    private CheckUpdateAmountResultDTO checkChannelPrepayAmount(WorkUpdateAmountDTO updateAmountDTO) throws OmsBaseException {
        Long orderId = updateAmountDTO.getOrderId();
        Long workId = updateAmountDTO.getWorkId();
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKeySrcMaster(orderId, workId);

        // 渠道预付
        Integer channelPrepayAmount = updateAmountDTO.getChannelPrepayAmount();
        if (channelPrepayAmount == null) {
            throw new OmsBaseException("非法操作 渠道预付为空");
        }

        // 订单金额
        Integer originalAmount = Optional.ofNullable(dbOrderWork.getOriginalAmount()).orElse(0);

        // 定金
        Integer depositAmount = Optional.ofNullable(dbOrderWork.getDepositAmount()).orElse(0);

        // 优惠金额
        Integer discountAmount = Optional.ofNullable(dbOrderWork.getDiscountAmount()).orElse(0);

        // 预付款 = 啄木鸟预付 + 渠道预付
        Integer prepayAmount = Optional.ofNullable(dbOrderWork.getPrepayAmount()).orElse(0);

        if (dbOrderWork.getOriginalAmount() != null) {
            // 边界公式：订单金额 ≥ 优惠 + 预付款 + 定金
            validateWorkAmount(originalAmount, discountAmount, prepayAmount, channelPrepayAmount, depositAmount);
        }

        CheckUpdateAmountResultDTO resultDTO = new CheckUpdateAmountResultDTO();
        resultDTO.setDbOrderWork(dbOrderWork);
        return resultDTO;
    }

    private CheckUpdateAmountResultDTO checkDiscountAmount(WorkAmountDTO workAmountDTO) throws OmsBaseException {
        Long orderId = workAmountDTO.getOrderId();
        Long workId = workAmountDTO.getWorkId();
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKeySrcMaster(orderId, workId);

        // 定金
        Integer discountAmount = workAmountDTO.getAmount();
        if (discountAmount == null) {
            throw new OmsBaseException("非法操作 优惠金额为空");
        }

        // 订单金额
        Integer originalAmount = Optional.ofNullable(dbOrderWork.getOriginalAmount()).orElse(0);

        // 定金
        Integer depositAmount = Optional.ofNullable(dbOrderWork.getDepositAmount()).orElse(0);

        // 渠道预付
        Integer channelPrepayAmount = Optional.ofNullable(dbOrderWork.getChannelPrepayAmount()).orElse(0);

        // 预付款 = 啄木鸟预付 + 渠道预付
        Integer prepayAmount = Optional.ofNullable(dbOrderWork.getPrepayAmount()).orElse(0);

        // 边界公式：订单金额 ≥ 优惠 + 预付款 + 定金
        // 不满足公式，非标准单提示：原价需大于：xx
        // 不满足公式，标准单提示：定金需小于：xx
        validateWorkAmount(originalAmount, discountAmount, prepayAmount, channelPrepayAmount, depositAmount);

        CheckUpdateAmountResultDTO resultDTO = new CheckUpdateAmountResultDTO();
        resultDTO.setDbOrderWork(dbOrderWork);
        return resultDTO;
    }

    /**
     * 校验工单边界值
     *
     * @param originalAmount      订单金额
     * @param discountAmount      优惠总金额
     * @param prepayAmount        啄木鸟预付
     * @param channelPrepayAmount 渠道预付
     * @param depositAmount       定金
     * @throws OmsBaseException
     */
    private void validateWorkAmount(
            Integer originalAmount,
            Integer discountAmount,
            Integer prepayAmount,
            Integer channelPrepayAmount,
            Integer depositAmount) throws OmsBaseException {

        // 原价小于等于的情况下，不做判断
        if (originalAmount <= 0) {
            return;
        }

        // 边界公式：订单金额 ≥ 优惠 + 预付款 + 定金
        // 不满足公式，非标准单提示：原价需大于：xx
        // 不满足公式，标准单提示：定金需小于：xx

        // 最小合法金额
        int minValidAmount = discountAmount + prepayAmount + channelPrepayAmount + depositAmount;
        int sub = originalAmount - minValidAmount;
        if (sub < 0) {
            logger.info("originalAmount[{}]discountAmount[{}]prepayAmount[{}]channelPrepayAmount[{}]depositAmount[{}]",
                    originalAmount,discountAmount,prepayAmount,channelPrepayAmount,depositAmount);
            throw new OmsBaseException(StatusConsts.STATUS_SUCCESS_NEXT, String.format("服务项目价格需大于：%.2f元", AmountUtil.fen2Yuan(minValidAmount).doubleValue()));
        }
    }

    /**
     * 更新工程师收款支付结果
     *
     * @param orderPayResultDRO
     */
    @Override
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_PAY)
    public void updateMasterAmountPayResult(OrderPayResultDRO orderPayResultDRO) {
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKeySrcMaster(orderPayResultDRO.getOrderId(), orderPayResultDRO.getWorkId());

        Integer originalAmount = null, totalAmount = null;
        // 实际支付金额和工单金额不相等，更新原价和总价
        if (!Objects.equals(dbOrderWork.getMasterAmount(), orderPayResultDRO.getAmount())) {
            int diffAmount = Optional.ofNullable(dbOrderWork.getMasterAmount()).orElse(0) - orderPayResultDRO.getAmount();

            // 有可能是支付优惠影响导致实际支付金额与orderWork记录的工程师收款额不相等
            if (CollectionUtil.isNotNullOrEmpty(orderPayResultDRO.getOrderPayDiscountList())) {
                Integer discountAmount = orderPayResultDRO.getOrderPayDiscountList().stream().mapToInt(OrderPayDiscountDIO::getAmount).sum();
                if (Objects.equals(diffAmount, discountAmount)) {
                    // 由于支付宝优惠券影响
                    originalAmount = Optional.ofNullable(dbOrderWork.getOriginalAmount()).orElse(0);
                    totalAmount = Optional.ofNullable(dbOrderWork.getTotalAmount()).orElse(0) - diffAmount;
                } else {
                    // 非支付宝优惠券影响 减去支付宝优惠的影响
                    diffAmount -= discountAmount;
                    originalAmount = Optional.ofNullable(dbOrderWork.getOriginalAmount()).orElse(0) - diffAmount;
                    totalAmount = Optional.ofNullable(dbOrderWork.getTotalAmount()).orElse(0) - diffAmount;
                }
            } else {
                originalAmount = Optional.ofNullable(dbOrderWork.getOriginalAmount()).orElse(0) - diffAmount;
                totalAmount = Optional.ofNullable(dbOrderWork.getTotalAmount()).orElse(0) - diffAmount;
            }

        }

        OrderWork orderWork = new OrderWork();
        orderWork.setOrderId(orderPayResultDRO.getOrderId());
        orderWork.setWorkId(orderPayResultDRO.getWorkId());
        orderWork.setMasterAmount(orderPayResultDRO.getAmount());
        orderWork.setMasterPayChannelId(orderPayResultDRO.getPayChannelId());
        orderWork.setMasterPayStatus(orderPayResultDRO.getPayStatus());
        orderWork.setMasterPayTime(orderPayResultDRO.getPayTime());
        orderWork.setPayTime(orderPayResultDRO.getPayTime());
        orderWork.setPayStatus(orderPayResultDRO.getPayStatus());
        orderWork.setOriginalAmount(originalAmount);
        orderWork.setTotalAmount(totalAmount);

        // 收单前 订单结果都是进行中
        // if (!Objects.equals(dbOrderWork.getResultStatus(), OrderStatusConsts.WORK_RESULT_DOING) && dbOrderWork.getStatus() < OrderStatusConsts.WORK_STATUS_CHECKOUT) {
        //     orderWork.setResultStatus(OrderStatusConsts.WORK_RESULT_DOING);
        // }
        orderWorkAmountService.updateMasterAmountPay(orderWork);
    }

    /**
     * 更新定金支付
     *
     * @param orderPayResultDRO
     */
    @Override
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_PAY)
    public void updateDepositAmountPayResult(OrderPayResultDRO orderPayResultDRO) {

        if (NumberUtil.isNotNullOrZero(orderPayResultDRO.getOrderPayId())) {
            OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderPayResultDRO.getOrderId(), orderPayResultDRO.getWorkId());
            OrderWork deposit = new OrderWork();
            deposit.setOrderId(orderWork.getOrderId());
            deposit.setWorkId(orderWork.getWorkId());
            // 对以前未支付定金兼容处理
            if (NumberUtil.isNotNullOrZero(orderWork.getDepositAmount()) && Objects.equals(orderWork.getDepositStatus(), PayConsts.PAY_STATUS_NONE)) {
                deposit.setDepositAmount(orderPayResultDRO.getAmount());
                deposit.setMasterAmount(orderWork.getDepositAmount() + orderWork.getMasterAmount() - orderPayResultDRO.getAmount());
            } else {
                deposit.setDepositAmount(Optional.ofNullable(orderWork.getDepositAmount()).orElse(0) + orderPayResultDRO.getAmount());
                deposit.setMasterAmount(Optional.ofNullable(orderWork.getMasterAmount()).orElse(0) - orderPayResultDRO.getAmount());
            }
            deposit.setDepositStatus(PayConsts.PAY_STATUS_DONE);
            deposit.setDepositChannelId(orderPayResultDRO.getPayChannelId());
            deposit.setDepositTime(orderPayResultDRO.getPayTime());
            deposit.setDisableDiscard(GlobalConsts.NO);// 禁用取消
            deposit.setUpdater(StringUtils.defaultString(orderPayResultDRO.getOperator(), "系统"));
            orderWorkService.updateOrderWorkByKey(deposit);
        } else {
            OrderWork orderWork = new OrderWork();
            orderWork.setOrderId(orderPayResultDRO.getOrderId());
            orderWork.setWorkId(orderPayResultDRO.getWorkId());
            orderWork.setDepositAmount(orderPayResultDRO.getAmount());
            orderWork.setDepositChannelId(orderPayResultDRO.getPayChannelId());
            orderWork.setDepositStatus(orderPayResultDRO.getPayStatus());
            orderWork.setDepositTime(orderPayResultDRO.getPayTime());
            orderWork.setDisableDiscard(GlobalConsts.NO);// 禁用取消
            orderWorkAmountService.updateDepositAmountPay(orderWork);
        }
    }

    /**
     * 更新啄木鸟预付款
     * @param orderPayResultDRO
     */
    @Override
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_PAY)
    public void updatePrepayAmountPayResult(OrderPayResultDRO orderPayResultDRO) {
        OrderWork orderWork = new OrderWork();
        orderWork.setOrderId(orderPayResultDRO.getOrderId());
        orderWork.setWorkId(orderPayResultDRO.getWorkId());
        orderWork.setPrepayAmount(orderPayResultDRO.getAmount());
        orderWork.setPrepayChannelId(orderPayResultDRO.getPayChannelId());
        orderWork.setPrepayStatus(orderPayResultDRO.getPayStatus());
        orderWork.setPrepayTime(orderPayResultDRO.getPayTime());
        orderWork.setDisableDiscard(GlobalConsts.NO);
        orderWorkAmountService.updatePrepayAmountPay(orderWork);
    }

    @Override
    public void updateOriginalAmountAfterPayment(WorkUpdateAmountDTO updateAmountDTO, OrderWork dbOrderWork) throws OmsBaseException {

        //  订单金额 >= 工程师收款金额 + 优惠总额 + 啄木鸟预收 + 定金 + 退款;
        Integer originalAmount = updateAmountDTO.getOriginalAmount();

        Integer masterAmount = dbOrderWork.getMasterAmount();
        masterAmount = Optional.ofNullable(masterAmount).orElse(0);

        Integer discountAmount = dbOrderWork.getDiscountAmount();
        discountAmount = Optional.ofNullable(discountAmount).orElse(0);

        Integer prepayAmount = dbOrderWork.getPrepayAmount();
        prepayAmount = Optional.ofNullable(prepayAmount).orElse(0);

        Integer depositAmount = dbOrderWork.getDepositAmount();
        depositAmount = Optional.ofNullable(depositAmount).orElse(0);

        Integer refundAmount = dbOrderWork.getRefundAmount();
        refundAmount = Optional.ofNullable(refundAmount).orElse(0);

        int minAmount = masterAmount + discountAmount + prepayAmount + depositAmount + refundAmount;
        if (originalAmount < minAmount) {
            throw new OmsBaseException(String.format("总价不能小于：%.2f元", AmountUtil.fen2Yuan(minAmount).doubleValue()));
        }

        // 渠道预付 = 订单金额 -（ 工程师收款金额 + 优惠总额 + 啄木鸟预收 + 定金 + 退款）;
        int channelPrepayAmount = originalAmount - minAmount;
        // 订单收入 = 订单金额 - 优惠总额 - 退款;
        int totalAmount = originalAmount - discountAmount - refundAmount;

        OrderWork updateOrderWork = new OrderWork();
        updateOrderWork.setOrderId(updateAmountDTO.getOrderId());
        updateOrderWork.setWorkId(updateAmountDTO.getWorkId());
        updateOrderWork.setOriginalAmount(originalAmount);
        updateOrderWork.setChannelPrepayAmount(channelPrepayAmount);
        updateOrderWork.setTotalAmount(totalAmount);
        orderWorkAmountService.updateOriginalAmountAfterPayment(updateOrderWork);
    }

    /**
     * 校验工单边界值，判断是否需要更新原价、订单收入、工程师收款金额
     *
     * @param validateWorkAmountDTO
     * @return
     */
    @Override
    public boolean validateWorkAmount(ValidateWorkAmountDTO validateWorkAmountDTO) throws OmsBaseException {
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKeySrcMaster(validateWorkAmountDTO.getOrderId(), validateWorkAmountDTO.getWorkId());

        WorkUpdateAmountDTO updateAmountDTO = new WorkUpdateAmountDTO();
        updateAmountDTO.setOrderId(dbOrderWork.getOrderId());
        updateAmountDTO.setWorkId(dbOrderWork.getWorkId());
        updateAmountDTO.setOriginalAmount(validateWorkAmountDTO.getOriginalAmount());

        // 优惠总金额
        ChangeOriginalAmountDiscountBO discountBO = getDiscountAmountByOriginalAmountChange(updateAmountDTO, dbOrderWork);
        Integer discountAmount = Optional.ofNullable(discountBO.getDiscountAmount()).orElse(0);

        // 订单金额
        Integer originalAmount = Optional.ofNullable(validateWorkAmountDTO.getOriginalAmount()).orElse(0);

        // 定金
        Integer depositAmount = Optional.ofNullable(dbOrderWork.getDepositAmount()).orElse(0);

        // 渠道预付
        Integer channelPrepayAmount = Optional.ofNullable(dbOrderWork.getChannelPrepayAmount()).orElse(0);

        // 预付款 = 啄木鸟预付 + 渠道预付
        Integer prepayAmount = Optional.ofNullable(dbOrderWork.getPrepayAmount()).orElse(0);

        // 边界公式：订单金额 ≥ 优惠 + 预付款 + 定金
        // 不满足公式，非标准单提示：原价需大于：xx
        // 不满足公式，标准单提示：定金需小于：xx

        // 最小合法金额
        int minValidAmount = discountAmount + prepayAmount + channelPrepayAmount + depositAmount;
        int sub = originalAmount - minValidAmount;
        return  sub >= 0;
    }

    /**
     * 更新退款结果
     *
     * @param refundResultDTO
     */
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_REFUND_RESULT)
    @Override
    public void updateRefundResult(WorkRefundResultDTO refundResultDTO) {
        if (!Objects.equals(refundResultDTO.getAllRefund(), GlobalConsts.YES)) {
            return;
        }
        // 全部退款才执行更新退款状态
        OrderWork upOrderWork = new OrderWork();
        upOrderWork.setOrderId(refundResultDTO.getOrderId());
        upOrderWork.setWorkId(refundResultDTO.getWorkId());
        upOrderWork.setPayStatus(refundResultDTO.getRefundResultDTO().getStatus());
        upOrderWork.setRefundTime(refundResultDTO.getRefundResultDTO().getRefundTime());
        upOrderWork.setUpdater(refundResultDTO.getOperator());
        if (Objects.equals(refundResultDTO.getStatus(), OrderStatusConsts.WORK_STATUS_COMPLETE)) {
            upOrderWork.setStatus(OrderStatusConsts.WORK_STATUS_COMPLETE);
            upOrderWork.setCompleteTime(DateUtil.getNow());
        }

        // 退款类型特殊处理
        String requestData = refundResultDTO.getRefundResultDTO().getRequestData();
        OmsRefundRequestDTO omsRefundRequestDTO = JSON.parseObject(requestData, OmsRefundRequestDTO.class);
        if (Objects.equals(omsRefundRequestDTO.getRefundInitiateType(), RefundInitiateTypeEnum.REFUND_DIFFERENCE.getType())) {
            upOrderWork.setMasterAmount(0);
            upOrderWork.setStatus(null);
            upOrderWork.setCompleteTime(null);
        }
        orderWorkAmountService.updateRefund(upOrderWork);
    }

    /**
     * 修正金额
     * @param orderId
     * @param workId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void fixedAmount(Long orderId,Long workId) {
        OrderWork dbOrderWork = orderWorkService.findOrderWorkByKeySrcMaster(orderId, workId);

        Integer factPayAmount = 0;
        if (Objects.equals(dbOrderWork.getChannelPrepayStatus(), PayConsts.PAY_STATUS_DONE) && !NumberUtil.isNullOrZero(dbOrderWork.getChannelPrepayAmount())) {
            factPayAmount = factPayAmount + dbOrderWork.getChannelPrepayAmount().intValue();
        }
        if (Objects.equals(dbOrderWork.getPrepayStatus(), PayConsts.PAY_STATUS_DONE) && !NumberUtil.isNullOrZero(dbOrderWork.getPrepayAmount())) {
            factPayAmount = factPayAmount + dbOrderWork.getPrepayAmount().intValue();
        }
        Integer depositAmount = dbOrderWork.getDepositAmount();
        if (Objects.equals(dbOrderWork.getDepositStatus(), PayConsts.PAY_STATUS_DONE) && !NumberUtil.isNullOrZero(depositAmount)) {
            factPayAmount = factPayAmount + depositAmount.intValue();
        }
        if (Objects.equals(dbOrderWork.getMasterPayStatus(), PayConsts.PAY_STATUS_DONE) && !NumberUtil.isNullOrZero(dbOrderWork.getMasterAmount())) {
            factPayAmount = factPayAmount + dbOrderWork.getMasterAmount().intValue();
        }
        if (NumberUtil.isNotNullOrZero(dbOrderWork.getDiscountPrepayAmount())) {
            factPayAmount = factPayAmount + dbOrderWork.getDiscountPrepayAmount().intValue();
        }
        if (Objects.equals(dbOrderWork.getFinalPrice(), GlobalConsts.YES)) {
            factPayAmount = MathUtil.sub(factPayAmount, dbOrderWork.getRefundAmount());
        }

        Integer newOriginalAmount = null;
        Integer newTotalAmount = null;
        Integer newDepositAmount = null;
        Integer newMasterAmount = null;

        Integer discountAmount = Optional.ofNullable(dbOrderWork.getDiscountAmount()).orElse(0);
        Integer discountPrepayAmount = Optional.ofNullable(dbOrderWork.getDiscountPrepayAmount()).orElse(0);
        Integer totalAmount = Optional.ofNullable(dbOrderWork.getTotalAmount()).orElse(0);
        Integer payDiscountAmount = Optional.ofNullable(dbOrderWork.getPayDiscountAmount()).orElse(0);

        // 支付金额不等于应收
        if (!Objects.equals(factPayAmount, totalAmount)) {
            newTotalAmount = factPayAmount;
            newOriginalAmount = newTotalAmount + discountAmount + payDiscountAmount;
            logger.info("[{}]纠正金额-支付金额[{}]不等于应收[{}]", workId, factPayAmount, totalAmount);
        }else {
            // 应收+优惠 <> 原价
            int amount = totalAmount + discountAmount - discountPrepayAmount + payDiscountAmount;
            if (Objects.equals(dbOrderWork.getFinalPrice(), GlobalConsts.YES)) {
                amount = amount + Optional.ofNullable(dbOrderWork.getRefundAmount()).orElse(0);
            }
            if (!Objects.equals(amount, dbOrderWork.getOriginalAmount())) {
                logger.info("[{}]纠正金额-应收[{}]+优惠[{}] + 支付优惠[{}]<>原价[{}]", workId, totalAmount, discountAmount, payDiscountAmount, dbOrderWork.getOriginalAmount());
                newOriginalAmount = totalAmount + discountAmount + payDiscountAmount;
            }
        }
        // 有未支付定金
        if (NumberUtil.isNotNullOrZero(depositAmount) && !Objects.equals(dbOrderWork.getDepositStatus(), PayConsts.PAY_STATUS_DONE)) {
            newDepositAmount = 0;
            logger.info("[{}]纠正金额-有未支付定金[{}]", workId, depositAmount);
        }
        // 有未支付师傅收款
        if (NumberUtil.isNotNullOrZero(dbOrderWork.getMasterAmount()) && !Objects.equals(dbOrderWork.getMasterPayStatus(), PayConsts.PAY_STATUS_DONE)) {
            newMasterAmount = 0;
            logger.info("[{}]纠正金额-有未支付是否收款[{}]", workId, depositAmount);
        }
        // 纠正服务项金额
        Integer factOriginalAmount = newOriginalAmount != null ? newOriginalAmount : dbOrderWork.getOriginalAmount();
        Integer serviceItemTotalPrice = 0;
        List<OrderServiceItem> orderServiceItems = orderServiceItemService.listByOrderId(orderId);
        if (CollectionUtil.isNotNullOrEmpty(orderServiceItems)) {
            serviceItemTotalPrice = orderServiceItems.stream().filter(e -> e.getTotalPrice() != null).mapToInt(e -> e.getTotalPrice()).sum();
        }
        if (!Objects.equals(factOriginalAmount, serviceItemTotalPrice)) {// 原价不等于服务项目，纠正服务项价格
            logger.info("[{}]纠正金额-原价[{}]不等于服务项金额[{}]之和", workId, factOriginalAmount, serviceItemTotalPrice);
            List<OrderProductExtend> orderProductExtendList = orderProductExtendService.listByOrderIdSrcMaster(orderId);
            orderServiceItemBService.deleteAndCreateFreeServiceItem(dbOrderWork, orderProductExtendList, factOriginalAmount);
        }

        // 更新金额
        if (newOriginalAmount != null || newTotalAmount != null || newDepositAmount != null) {
            OrderWork orderWork = new OrderWork();
            orderWork.setOrderId(dbOrderWork.getOrderId());
            orderWork.setWorkId(dbOrderWork.getWorkId());
            orderWork.setOriginalAmount(newOriginalAmount);
            orderWork.setTotalAmount(newTotalAmount);
            orderWork.setDepositAmount(newDepositAmount);
            orderWork.setMasterAmount(newMasterAmount);
            orderWorkAmountService.updateOriginalAndTotalAndDepositAmount(orderWork);
        }

    }


    /**
     * 更新工单金额和优惠列表
     *
     * @param orderAmountCalcBO
     * @param orderWork
     */
    @Override
    public void updateAmountAndDiscount(OrderAmountCalcBO orderAmountCalcBO, OrderWork orderWork) throws OmsBaseException {

        // 1，保存优惠
        OrderDiscountCalcBO orderDiscountCalcBO = orderAmountCalcBO.getOrderDiscountCalcBO();
        if (orderDiscountCalcBO != null) {
            // 保存优惠 (先删后增)
            orderDiscountBService.saveOrderDiscountList(orderDiscountCalcBO.getOrderDiscountList(), orderWork.getOrderId());

            // 核销优惠券
            List<OrderDiscount> receiptConsumeDiscounts = orderDiscountCalcBO.getReceiptConsumeDiscountList();
            if (CollectionUtil.isNotNullOrEmpty(receiptConsumeDiscounts)) {
                // 排除口碑核销
                List<OrderDiscount> receiptConsumeDiscountList = receiptConsumeDiscounts.stream()
                        .filter(e -> !Objects.equals(e.getThirdCoupPlat(), ThirdPlatEnum.THIRD_COUP_TYPE_KB.getKey())
                                && !Objects.equals(e.getThirdCoupPlat(), ThirdPlatEnum.THIRD_COUP_TYPE_MT.getKey()))
                        .collect(Collectors.toList());
               // 核销
                orderDiscountCalcBService.receiptConsumeDiscount(receiptConsumeDiscountList, orderDiscountCalcBO.getInvoker(), orderAmountCalcBO.getOriginalAmount(), orderWork, null,GlobalConsts.SPLITER_EMPTY,GlobalConsts.SPLITER_EMPTY);
            }
            // 归还优惠券
            if (CollectionUtil.isNotNullOrEmpty(orderDiscountCalcBO.getBackDiscountList())) {
                orderDiscountCalcBService.backDiscount(orderDiscountCalcBO.getBackDiscountList());
            }

        }

        // 2，更新工单金额
        OrderWork updateOrderWork = new OrderWork();
        updateOrderWork.setOrderId(orderWork.getOrderId());
        updateOrderWork.setWorkId(orderWork.getWorkId());
        updateOrderWork.setOriginalAmount(orderAmountCalcBO.getOriginalAmount());
        updateOrderWork.setTotalAmount(orderAmountCalcBO.getTotalAmount());
        updateOrderWork.setPrepayAmount(orderAmountCalcBO.getPrepayAmount());
        updateOrderWork.setChannelPrepayAmount(orderAmountCalcBO.getChannelPrepayAmount());
        updateOrderWork.setDepositAmount(orderAmountCalcBO.getDepositAmount());
        updateOrderWork.setMasterAmount(orderAmountCalcBO.getMasterAmount());
        updateOrderWork.setDiscountAmount(orderAmountCalcBO.getDiscountAmount());
        updateOrderWork.setDiscountPrepayAmount(orderAmountCalcBO.getDiscountPrepayAmount());
        updateOrderWork.setOnlyVisit(orderAmountCalcBO.getOnlyVisit());
        updateOrderWork.setPayDiscountAmount(orderAmountCalcBO.getPayDiscountAmount());

        if (NumberUtil.isNotNullOrZero(orderAmountCalcBO.getFullPaymentFlag())) {
            updateOrderWork.setFullPaymentFlag(orderAmountCalcBO.getFullPaymentFlag());
        }

        // 验券，渠道代收不为空，设为已支付状态
        if (Objects.equals(orderAmountCalcBO.getTriggerAmountChangeEnum(), TriggerAmountChangeEnum.VALIDATE_COUPON)
                && NumberUtil.isNotNullOrZero(orderAmountCalcBO.getChannelPrepayAmount())) {
            updateOrderWork.setChannelPrepayStatus(PayConsts.PAY_STATUS_DONE);
        }
        logger.info("[{}]更新金额==>{}", orderWork.getWorkId(), JSON.toJSONString(updateOrderWork));
        orderWorkAmountService.updateAmount(updateOrderWork);
        // 验券获取售价
        if (Objects.nonNull(orderDiscountCalcBO) && Objects.equals(orderAmountCalcBO.getTriggerAmountChangeEnum(), TriggerAmountChangeEnum.VALIDATE_COUPON)) {
            this.sendQueueGetThirdSellAmount(orderDiscountCalcBO.getOrderDiscountList(), orderWork);
        }
    }

    private void sendQueueGetThirdSellAmount(List<OrderDiscount> list, OrderWork orderWork) {
        if (CollectionUtil.isNullOrEmpty(list)) {
            return;
        }
        List<OrderDiscount> mtList = list.stream()
                .filter(e -> Objects.equals(e.getThirdCoupPlat(), ThirdPlatEnum.THIRD_COUP_TYPE_MT.getKey()) && Objects.equals(e.getThirdCode(), GlobalConsts.YES))
                .collect(Collectors.toList());
        if (CollectionUtil.isNullOrEmpty(mtList)) {
            log.info("非美团获取售价");
            return;
        }

        OrderDiscount mtDiscount = mtList.get(0);
        if (NumberUtil.isNullOrZero(mtDiscount.getSellAmount())) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("orderId", orderWork.getOrderId());
            jsonObject.put("cityId", orderWork.getCityId());
            jsonObject.put("channelId", orderWork.getChannelId());
            jsonObject.put("itemCode", mtDiscount.getItemCode());
            String key = String.valueOf(orderWork.getOrderId());
            String message = jsonObject.toJSONString();
            log.info("发送获取美团售价队列tag:{}，key：{},message：{}", MessageQueueTagConsts.OMS_THIRD_COUPON_SALE_PRICE, key, message);
            zmnMQSender.send(MessageQueueTopicConstant.ZMN_TOPIC_OMS, MessageQueueTagConsts.OMS_THIRD_COUPON_SALE_PRICE, key, message);
        }else {
            log.info("美团获取售价-已有售价不获取--->{}", mtDiscount.getSellAmount());
        }
    }

    /**
     * 异常支付
     * @param orderPayResultDRO
     */
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_EXCEPTION_ORDER_PAY)
    @Override
    public void addExceptionOrderPay(OrderPayResultDRO orderPayResultDRO) {

    }
}
